#pragma once
#include <common.hpp>
#include "Vector.hpp"
#undef min
#undef max

namespace zzz{
template <typename T>
class Vector<3, T> : public VectorBase<3, T>
{
protected:
  using VectorBase<3, T>::v;
public:
  //constructor
  Vector(void){}
  Vector(const Vector<3, T>& a):VectorBase<3, T>(a){}
  Vector(const T &a,const T &b,const T &c){v[0]=a; v[1]=b; v[2]=c;}
  Vector(const VectorBase<3, T>& a):VectorBase<3, T>(a){}
  explicit Vector(const T &a):VectorBase<3, T>(a){}
  explicit Vector(const VectorBase<2, T> &a, const T &b):VectorBase<3, T>(a, b){}
  explicit Vector(const VectorBase<4, T> &a):VectorBase<3, T>(a){}
  template<typename T1> explicit Vector(const T1 *p):VectorBase<3, T>(p){}
  template<typename T1> explicit Vector(const Vector<3,T1>& a):VectorBase<3, T>(a){}
  template<typename T1> explicit Vector(const VectorBase<3,T1>& a):VectorBase<3, T>(a){}

  inline const Vector<3, T> &operator=(const Vector<3, T>& a){VectorBase<3, T>::operator =(a); return *this;}
  inline void Set(const T &a, const T &b, const T &c){v[0]=a; v[1]=b; v[2]=c;}
  using VectorBase<3, T>::operator=;

  // Vector3 only cross
  inline Vector<3, T> Cross(const Vector<3, T> &a) const 
  {
    return Vector<3, T>(v[1]*a.v[2]-v[2]*a.v[1], v[2]*a.v[0]-v[0]*a.v[2], v[0]*a.v[1]-v[1]*a.v[0]);
  }

  // alias
  inline T& x(){return v[0];}
  inline T& y(){return v[1];}
  inline T& z(){return v[2];}
  inline T& r(){return v[0];}
  inline T& g(){return v[1];}
  inline T& b(){return v[2];}
  inline T& i(){return v[0];}
  inline T& j(){return v[1];}
  inline T& k(){return v[2];}
  inline const T& x() const {return v[0];}
  inline const T& y() const {return v[1];}
  inline const T& z() const {return v[2];}
  inline const T& r() const {return v[0];}
  inline const T& g() const {return v[1];}
  inline const T& b() const {return v[2];}
  inline const T& i() const {return v[0];}
  inline const T& j() const {return v[1];}
  inline const T& k() const {return v[2];}

};

typedef Vector<3,zint8> Vector3i8;
typedef Vector<3,zuint8> Vector3ui8;
typedef Vector<3,zint8> Vector3i16;
typedef Vector<3,zuint8> Vector3ui16;
typedef Vector<3,zint8> Vector3i32;
typedef Vector<3,zuint8> Vector3ui32;
typedef Vector<3,zint8> Vector3i64;
typedef Vector<3,zuint8> Vector3ui64;
typedef Vector<3,zfloat32> Vector3f32;
typedef Vector<3,zfloat64> Vector3f64;


typedef Vector<3,zuchar> Vector3uc;
typedef Vector<3,zuint> Vector3ui;
typedef Vector<3,int> Vector3i;
typedef Vector<3,float> Vector3f;
typedef Vector<3,double> Vector3d;


template<typename T>
inline Vector<3, T> Cross(const VectorBase<3, T> &a, const VectorBase<3, T> &b)
{
  return Vector<3, T>(a[1]*b[2]-a[2]*b[1], a[2]*b[0]-a[0]*b[2], a[0]*b[1]-a[1]*b[0]);
}

template<typename T>
inline void Cross(const VectorBase<3, T> &a, const VectorBase<3, T> &b, VectorBase<3, T> &res)
{
  res[0]=a[1]*b[2]-a[2]*b[1];
  res[1]=a[2]*b[0]-a[0]*b[2];
  res[2]=a[0]*b[1]-a[1]*b[0];
}

}
